`define CSR_CRMD   0
`define CSR_PRMD   1
`define CSR_ECFG   4 
`define CSR_ESTAT  5
`define CSR_ERA    6
`define CSR_EENTRY 12
`define CSR_SAVE0  48
`define CSR_SAVE1  49
`define CSR_SAVE2  50
`define CSR_SAVE3  51

`define CSR_TICLR  68
//Lab 9 add
`define CSR_BADV   7
`define CSR_TID    64
`define CSR_TCFG   65
`define CSR_TVAL   66



module csrr (
    input         clk   ,
    input         reset ,
    input         wb_ex ,
    input  [7 :0] hw_int_in, 
    input  [0 :0] ipi_int_in,
    input  [31:0] ws_pc ,
    input  [31:0] ws_pc_e,
    input  [31:0] wb_vaddr ,
    input         ertn_reflush,
    input  [13:0] csr_num,
    input         csr_we,
    input  [31:0] csr_wmask,
    input  [31:0] csr_wvalue,
    input  [5 :0] wb_ecode,
    input  [8 :0] wb_esubcode,
    input  [31:0] coreid_in,
    output [31:0] csr_rvalue,
    //If this is int
    output [0: 0] has_int   ,
    //Control Reg
    output [31:0] csr_crmd  ,
    output [31:0] csr_prmd  ,
    output [31:0] csr_era   ,
    output [31:0] csr_ecfg  , 
    output [31:0] csr_eentry,
    output [31:0] csr_estat ,
    output [31:0] csr_save0 ,
    output [31:0] csr_save1 ,
    output [31:0] csr_save2 ,
    output [31:0] csr_save3 ,
    //Lab 9 add
    output [31:0] csr_badv  ,
    output [31:0] csr_tid   ,
    output [31:0] csr_tcfg  ,
    output [31:0] csr_tval  ,
    output [31:0] csr_ticlr
);

/*reg  [31:0] csr_reg [180:0];

//These signals aim to get the right write answer
wire [31:0] csr_mask;
wire [31:0] write_mask;
wire [31:0] csr_wvalue_t;
assign csr_mask     = ~csr_wmask & csr_reg[csr_num];       //Clear the need writing bit 0!!
assign write_mask   = csr_wmask  & csr_wvalue;             //Clear the write data which don't need writing 0
assign csr_wvalue_t = csr_mask   | write_mask;             //Then we get the right write data

//Below is to write data into CSR register
always @(posedge clk) begin
    if(csr_we) begin
        csr_reg[csr_num] <= csr_wvalue_t;
    end
end

//Below is to read data
assign csr_rvalue = csr_reg[csr_num];                
*/
//Below we want to realize the special registers QQQQQAQQQQQ

//CRMD REGISTERS BEGIN!
/*Important NOTE: wb_ex, we don't realize it now!!*/

/*PLV Field*/
reg [1:0] csr_crmd_plv;
reg [1:0] csr_prmd_pplv;

always@(posedge clk) begin
    if(reset) begin
        csr_crmd_plv <= 2'b0;
    end
    else if (wb_ex) begin
        csr_crmd_plv <= 2'b0;
    end
    else if (ertn_reflush) begin
        csr_crmd_plv <= csr_prmd_pplv;
    end
    else if (csr_we && csr_num==`CSR_CRMD) begin
        csr_crmd_plv <= csr_wmask[1:0] & csr_wvalue[1:0] | ~csr_wmask[1:0] & csr_crmd_plv;
    end
end

/*IE Field*/
reg [0:0] csr_crmd_ie;
reg [0:0] csr_prmd_pie;

always @(posedge clk) begin
    if(reset) begin
        csr_crmd_ie <= 1'b0;
    end
    else if(wb_ex) begin
        csr_crmd_ie <= 1'b0;
    end
    else if(ertn_reflush) begin
        csr_crmd_ie <= csr_prmd_pie; 
    end
    else if(csr_we && csr_num==`CSR_CRMD) begin
        csr_crmd_ie <= csr_wmask[2] & csr_wvalue[2] | ~csr_wmask[2] & csr_crmd_ie;
    end
end

//Now is direct address visiting. NO TLB!
assign csr_crmd = {28'b0, 1'b1/*DA*/, csr_crmd_ie/*IE*/, csr_crmd_plv/*PLV*/};

//Below is the PRMD REGISTERS!!!

/*PPLV and PIE*/
always @(posedge clk) begin
    if(wb_ex) begin
        csr_prmd_pplv <= csr_crmd_plv;
        csr_prmd_pie  <= csr_crmd_ie ;
    end
    else if(csr_we && csr_num == `CSR_PRMD) begin
        csr_prmd_pplv <= csr_wmask[1:0] & csr_wvalue[1:0] | ~csr_wmask[1:0] & csr_prmd_pplv;
        csr_prmd_pie  <= csr_wmask[2]   & csr_wvalue[2]   | ~csr_wmask[2]   & csr_prmd_pie;
    end
end

assign csr_prmd = {29'b0/*R0*/, csr_prmd_pie/*PIE*/, csr_prmd_pplv/*PPLV*/};

//Below is the ESTAT REGISTERS!!
reg [12:0] csr_estat_is;
reg [31:0] timer_cnt;

/*Timer_cnt*/
//always @(posedge clk) begin
//    if(reset) begin
//        timer_cnt <= 32'hffffffff;
//    end else begin
//        timer_cnt <= timer_cnt - 1'b1;
//    end
//end


/*IS field*/
always @(posedge clk) begin
    if(reset) begin
        csr_estat_is[1:0] <= 2'b0;
    end
    else if(csr_we && csr_num == `CSR_ESTAT) begin
        csr_estat_is[1:0] <= csr_wmask[1:0] & csr_wvalue[1:0] | ~csr_wmask[1:0] & csr_estat_is[1:0];
    end

    csr_estat_is[9:2] <= hw_int_in[7:0];    
    csr_estat_is[10]  <= 1'b0;          //This bit is not defined
    csr_estat_is[12]  <= ipi_int_in;    //Between Core int
end

always @(posedge clk ) begin
    if (timer_cnt[31:0]==32'b0) begin
        csr_estat_is[11] <= 1'b1;
    end
    else if (csr_we && csr_num ==`CSR_TICLR && csr_wmask[0] && csr_wvalue[0]) begin
        csr_estat_is[11] <= 1'b0;
    end
end

/*Ecode and EsubCode field*/
reg [5:0] csr_estat_ecode;
reg [5:0] csr_estat_esubcode;

always @(posedge clk) begin
    if(wb_ex) begin
        csr_estat_ecode    <= wb_ecode;
        csr_estat_esubcode <= wb_esubcode;
    end
end

assign csr_estat = {1'b0/*R0*/, csr_estat_esubcode/*ESUBCODE*/,csr_estat_ecode/*ECODE*/, 3'b0, 
                    csr_estat_is};

//Below is ERA register!!
reg [31:0] csr_era_pc;

always @(posedge clk) begin
    if(wb_ex) begin
        csr_era_pc <= ws_pc_e;
    end
    else if(csr_we && csr_num == `CSR_ERA) begin
        csr_era_pc <= csr_wmask[31:0] & csr_wvalue[31:0] | ~csr_wmask[31:0] & csr_era_pc;
    end
end

assign csr_era = csr_era_pc;

//Below is EENTRY register!!
reg [25:0] csr_eentry_va;

always @(posedge clk) begin
    if (csr_we && csr_num == `CSR_EENTRY) begin
        csr_eentry_va <= csr_wmask[31:6] & csr_wvalue[31:6] | ~csr_wmask[31:6] & csr_eentry_va;
    end
end

assign csr_eentry = {csr_eentry_va/*VA*/, 6'b0/*0*/};

//Below is SAVE 0-3 register!!
reg [31:0] csr_save0_data;
reg [31:0] csr_save1_data;
reg [31:0] csr_save2_data;
reg [31:0] csr_save3_data;

/*Save 0 register*/
always @(posedge clk) begin
    if(csr_we && csr_num == `CSR_SAVE0) begin
        csr_save0_data <= csr_wmask[31:0] & csr_wvalue[31:0] | ~csr_wmask[31:0] & csr_save0_data;
    end
end

assign csr_save0 = csr_save0_data;

/*Save 1 register*/
always @(posedge clk) begin
    if(csr_we && csr_num == `CSR_SAVE1) begin
        csr_save1_data <= csr_wmask[31:0] & csr_wvalue[31:0] | ~csr_wmask[31:0] & csr_save1_data;
    end
end

assign csr_save1 = csr_save1_data;

/*Save 2 register*/
always @(posedge clk) begin
    if(csr_we && csr_num == `CSR_SAVE2) begin
        csr_save2_data <= csr_wmask[31:0] & csr_wvalue[31:0] | ~csr_wmask[31:0] & csr_save2_data;
    end
end

assign csr_save2 = csr_save2_data;

/*Save 3 register*/
always @(posedge clk) begin
    if(csr_we && csr_num == `CSR_SAVE3) begin
        csr_save3_data <= csr_wmask[31:0] & csr_wvalue[31:0] | ~csr_wmask[31:0] & csr_save3_data;
    end
end

assign csr_save3 = csr_save3_data;

/*ECFG register*/
reg [12:0] csr_ecfg_lie;
always @(posedge clk) begin
    if(reset) begin
        csr_ecfg_lie <= 13'b0;
    end 
    else if(csr_we & csr_num == `CSR_ECFG) begin
        csr_ecfg_lie <= csr_wmask[12:0] & csr_wvalue[12:0] | ~csr_wmask[12:0] & csr_ecfg_lie;
    end
end

assign csr_ecfg = {19'b0, csr_ecfg_lie};

/*LAB9 ADD REG*/
/*BADV register*///ECODE_ADE ^^^=?,
reg [31:0] csr_badv_vaddr;
assign wb_ex_addr_err = wb_ecode==6'h08 || wb_ecode==6'h09;

always @(posedge clk) begin
    if (wb_ex && wb_ex_addr_err)
        csr_badv_vaddr <= (wb_ecode==6'h08 & wb_esubcode==9'b0) ? ws_pc_e : wb_vaddr;
end

assign csr_badv = {csr_badv_vaddr};

/*TID register*/
reg [31:0] csr_tid_tid;
always @(posedge clk) begin
    if (reset)
        csr_tid_tid <= coreid_in;
    else if (csr_we & csr_num==`CSR_TID)
        csr_tid_tid <= csr_wmask[31:0]&csr_wvalue[31:0] | ~csr_wmask[31:0] & csr_tid_tid;
end
assign csr_tid = {csr_tid_tid};

/*TCFG register*/
reg [0 :0] csr_tcfg_en;
reg [0 :0] csr_tcfg_periodic;
always @(posedge clk) begin
    if (reset)
        csr_tcfg_en <= 1'b0;
    else if (csr_we & csr_num==`CSR_TCFG)
        csr_tcfg_en <= csr_wmask[0]&csr_wvalue[0] | ~csr_wmask[0]&csr_tcfg_en;
    if (csr_we && csr_num==`CSR_TCFG) begin
        csr_tcfg_periodic <= csr_wmask[1]&csr_wvalue[1] | ~csr_wmask[1]&csr_tcfg_periodic;
        csr_tcfg_initval <= csr_wmask[31:2]&csr_wvalue[31:2] | ~csr_wmask[31:2]&csr_tcfg_initval;
    end
end
assign csr_tcfg = {csr_tcfg_initval, csr_tcfg_periodic, csr_tcfg_en};

/*TVAL register*/
reg [29:0] csr_tcfg_initval;
wire [31:0] tcfg_next_value;
assign tcfg_next_value = csr_wmask[31:0]&csr_wvalue[31:0]
                        | ~csr_wmask[31:0]&{csr_tcfg_initval, csr_tcfg_periodic, csr_tcfg_en};
always @(posedge clk) begin
    if (reset)
        timer_cnt <= 32'hffffffff;
    else if (csr_we && csr_num==`CSR_TCFG && tcfg_next_value[0])
        timer_cnt <= {tcfg_next_value[31:2], 2'b0};
    else if (csr_tcfg_en && timer_cnt!=32'hffffffff) begin
        if (timer_cnt[31:0]==32'b0 && csr_tcfg_periodic)
            timer_cnt <= {csr_tcfg_initval, 2'b0};
        else
            timer_cnt <= timer_cnt - 1'b1;
    end
end
assign csr_tval = timer_cnt[31:0];

//TICLR register
assign csr_ticlr_clr = 1'b0;
assign csr_ticlr = 32'b0;



//Read data defined HERE!!
assign csr_rvalue = {32{csr_num == `CSR_CRMD}}   & csr_crmd   |
                    {32{csr_num == `CSR_PRMD}}   & csr_prmd   |
                    {32{csr_num == `CSR_ERA }}   & csr_era    |
                    {32{csr_num == `CSR_EENTRY}} & csr_eentry |
                    {32{csr_num == `CSR_ESTAT}}  & csr_estat  |
                    {32{csr_num == `CSR_SAVE0}}  & csr_save0  |
                    {32{csr_num == `CSR_SAVE1}}  & csr_save1  |
                    {32{csr_num == `CSR_SAVE2}}  & csr_save2  |
                    {32{csr_num == `CSR_SAVE3}}  & csr_save3  |
                    {32{csr_num == `CSR_ECFG}}   & csr_ecfg   |
                    {32{csr_num == `CSR_BADV}}   & csr_badv   |
                    {32{csr_num == `CSR_TID}}    & csr_tid    |
                    {32{csr_num == `CSR_TCFG}}   & csr_tcfg   |
                    {32{csr_num == `CSR_TVAL}}   & csr_tval   |
                    {32{csr_num == `CSR_TICLR}}  & csr_ticlr  ;

assign has_int = ((csr_estat_is[11:0] & csr_ecfg_lie[11:0]) != 12'b0) && (csr_crmd_ie == 1'b1);

endmodule 